//------------------------------------------------------------------------------
// Utils.cpp
//------------------------------------------------------------------------------
// Copyright 1995-2006 Microsoft Corporation.  All Rights Reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 
// PARTICULAR PURPOSE.
//------------------------------------------------------------------------------
//
// Utility/helper functions
//
//------------------------------------------------------------------------------

#include "stdpch.h"
#include <msiquery.h>
#include "Utils.h"
#include "MemUtils.h"
#include "StackString.h"

#pragma comment(lib, "msi.lib")

HRESULT LoadAndLockResource(__in HINSTANCE hinst, UINT uiResID, PCWSTR pszType, __out void **ppvRes, __out DWORD *pcb)
{
    *ppvRes = NULL;

    // Find the resource
    HRSRC hrsrc;
    hrsrc = FindResource(hinst, MAKEINTRESOURCE(uiResID), pszType);
    HRESULT hr = hrsrc ? S_OK : HRESULT_FROM_WIN32(GetLastError());
    if (SUCCEEDED(hr))
    {
        // Get the size of the resource
        *pcb = SizeofResource(hinst, hrsrc);
        hr = *pcb ? S_OK : AtlHresultFromLastError();
        if (SUCCEEDED(hr))
        {
            HGLOBAL hmem;
            hmem = LoadResource(hinst, hrsrc);
            hr = hmem ? S_OK : AtlHresultFromLastError();
            if (SUCCEEDED(hr))
            {
                *ppvRes = LockResource(hmem);
                if (!*ppvRes)
                {
                    hr = E_FAIL;
                }
            }
        }
    }
    return hr;
}

HRESULT LoadPopupMenu(__in HINSTANCE hinst, UINT uiResID, __out HMENU *phmnu)
{
    *phmnu = NULL;
    HMENU hmnu = LoadMenu(hinst, MAKEINTRESOURCE(uiResID));
    HRESULT hr = hmnu ? S_OK : AtlHresultFromLastError();
    if (SUCCEEDED(hr))
    {
        HMENU hmnuPopup = GetSubMenu(hmnu, 0);
        hr = hmnuPopup ? S_OK : AtlHresultFromLastError();
        if (SUCCEEDED(hr))
        {
            hr = RemoveMenu(hmnu, 0, MF_BYPOSITION) ? S_OK : AtlHresultFromLastError();
            if (SUCCEEDED(hr))
            {
                *phmnu = hmnuPopup;
            }
        }
        DestroyMenu(hmnu);
    }
    return hr;
}

void SetThreadName(DWORD dwThreadID, const char *pszThreadName)
{
    typedef struct tagTHREADNAME_INFO
    {
        DWORD_PTR dwType;      // must be 0x1000
        const char *pszName;   // pointer to name
        DWORD_PTR dwThreadID;  // thread ID (-1 = caller thread)
        DWORD_PTR dwFlags;     // reserved for future use, must be zero;
    } THREADNAME_INFO;

    THREADNAME_INFO info;
    info.dwType = 0x1000;
    info.pszName = pszThreadName;
    info.dwFlags = 0;
    info.dwThreadID = (int)dwThreadID;

    __try
    {
        RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD_PTR), reinterpret_cast<DWORD_PTR*>(&info));
    }
    __except (EXCEPTION_CONTINUE_EXECUTION)
    {
    }
}

STDAPI PathGetNarrowPath(__in PCWSTR pszPath, __deref_out PWSTR *ppszNarrowPath)
{
    *ppszNarrowPath = NULL;

    CComMemPtr<WCHAR> spszTemp;
    HRESULT hr = SHStrDup(pszPath, &spszTemp);
    if (SUCCEEDED(hr))
    {
        CStackString<1024> strPath;
        PWSTR pszSplit = PathFindFileName(spszTemp);
        if (pszSplit > spszTemp)
        {
            *(pszSplit - 1) = L'\0'; // separate preceeding path from this path segment
            hr = strPath.Format(L"%s (%s)", pszSplit, spszTemp);
            if (SUCCEEDED(hr))
            {
                hr = strPath.CoTaskMemCopy(ppszNarrowPath);
            }
        }
        else
        {
            // we already have a narrow path
            *ppszNarrowPath = spszTemp.Detach();
        }
    }
    return hr;
}

HRESULT GetMsiProperty(MSIHANDLE hmsi, PCWSTR pszPropName, __deref_out PWSTR *ppszProp)
{
    HRESULT hr = E_FAIL;
    DWORD cch = 0;
    if (ERROR_MORE_DATA == MsiGetProperty(hmsi, pszPropName, L"", &cch))
    {
        cch++;
        CComMemPtr<WCHAR> spszProp;
        hr = spszProp.Allocate(cch);
        if (SUCCEEDED(hr))
        {
            hr = AtlHresultFromWin32(MsiGetProperty(hmsi, pszPropName, spszProp, &cch));
            if (SUCCEEDED(hr))
            {
                *ppszProp = spszProp.Detach();
            }
        }
    }
    return hr;
}
